package tuanda.soict.firstsun.LogicPackage;

import java.util.ArrayList;

import tuanda.soict.firstsun.AbilityPackage.Ability;
import tuanda.soict.firstsun.BuildingPackage.Army_Building;
import tuanda.soict.firstsun.BuildingPackage.Building;
import tuanda.soict.firstsun.BuildingPackage.HQ_Building;
import tuanda.soict.firstsun.DataPackage.AbilityList;
import tuanda.soict.firstsun.DataPackage.ArmyDataSet;

/**
 * @author tuanda_soict_hut
 * @version 0.1.2
 * @since 14-10-2012
 */
public class AI_Part extends Scenario implements AbilityList {

	private Army_Building[] sortedArmyBuilding;
	private Army_Building chosenArmyBuilding;
	private ArmyDataSet chosenArmy;
	private ArrayList<AlternativeCoordinate> alternativePath;
	private boolean isBuyCompleted;
	private int currentIndex;

	public AI_Part(BattleMap batMap, Group[] gro, int firstTurn,
			int[] playType, ArrayList<Building> neutral) {
		super(batMap, gro, firstTurn, playType, neutral);
		setSortedArmyBuilding(null);
		initializeAlternativePath();
	}

	@Override
	public void endScenario() {
	}

	public final boolean isBuyCompleted() {
		return isBuyCompleted;
	}

	public final void setBuyCompleted(boolean isCompleted) {
		this.isBuyCompleted = isCompleted;
	}

	public final void increaseCurrentIndex() {
		this.currentIndex++;
	}

	public final int getCurrentIndex() {
		return currentIndex;
	}

	public final void setCurrentIndex(int index) {
		this.currentIndex = index;
	}

	public final void setSortedArmyBuilding(Army_Building[] build) {
		this.sortedArmyBuilding = build;
	}

	public final Army_Building[] getSortedArmyBuilding() {
		return this.sortedArmyBuilding;
	}

	public final Army_Building getChosenArmyBuilding() {
		return this.chosenArmyBuilding;
	}

	public final void setChosenArmyBuilding(Army_Building army_build) {
		this.chosenArmyBuilding = army_build;
	}

	public final ArmyDataSet getChosenArmy() {
		return this.chosenArmy;
	}

	public final void setChosenArmy(ArmyDataSet army) {
		this.chosenArmy = army;
	}

	public final void initializeAlternativePath() {
		this.alternativePath = new ArrayList<AlternativeCoordinate>();
	}

	public final ArrayList<AlternativeCoordinate> getAlternativePath() {
		return this.alternativePath;
	}

	public final void setAlternativePath(ArrayList<AlternativeCoordinate> alter) {
		this.alternativePath = alter;
	}

	public final boolean prepareGenerateNewArmy(Group currentGroup) {
		createProduceArmyBuilding(currentGroup);
		if (getSortedArmyBuilding() != null) {
			setChosenArmy(null);
			setChosenArmyBuilding(null);
			mergeSort(0, getSortedArmyBuilding().length - 1);
			int gold = currentGroup.getIncome();
			int type = currentGroup.getType();
			int x, y;
			for (int i = currentIndex; i < getSortedArmyBuilding().length; i++) {
				x = sortedArmyBuilding[i].getLocationX();
				y = sortedArmyBuilding[i].getLocationY();
				int armyProduceType = sortedArmyBuilding[i]
						.getArmyProduceType();
				ArmyDataSet armyData = ArmyDataSet.SOLDIER.findAppropriateArmy(
						type, gold, armyProduceType);
				if (armyData != null) {
					Army arm = map.getArmy(x, y);
					if (arm != null) {
						if (arm.getGroupID() == currentGroup.getID()) {
							if (isMoveable(arm) == true) {
								setChosenArmy(armyData);
								setChosenArmyBuilding(sortedArmyBuilding[i]);
								return true;
							}
						}
					} else {
						setChosenArmy(armyData);
						setChosenArmyBuilding(sortedArmyBuilding[i]);
						return true;
					}
				}
			}
			isBuyCompleted = true;
		}
		isBuyCompleted = true;
		return false;
	}

	public final void mergeSort(int low, int high) {
		if ((high - low) > 0) {
			int middle = (low + high) / 2;
			mergeSort(low, middle);
			mergeSort(middle + 1, high);
			merge(low, middle, middle + 1, high);
		}
	}

	public final void merge(int left, int middle1, int middle2, int right) {
		int leftIndex = left;
		int rightIndex = middle2;
		int combinedIndex = left;
		Army_Building[] army_build = new Army_Building[sortedArmyBuilding.length];

		while (leftIndex <= middle1 && rightIndex <= right) {
			if (sortedArmyBuilding[leftIndex].getDistance() < sortedArmyBuilding[rightIndex]
					.getDistance()) {
				army_build[combinedIndex] = sortedArmyBuilding[leftIndex];
				combinedIndex++;
				leftIndex++;
			} else {
				army_build[combinedIndex] = sortedArmyBuilding[rightIndex];
				combinedIndex++;
				rightIndex++;
			}
		}

		if (leftIndex == middle2) {
			while (rightIndex <= right) {
				army_build[combinedIndex] = sortedArmyBuilding[rightIndex];
				combinedIndex++;
				rightIndex++;
			}
		} else {
			while (leftIndex <= middle1) {
				army_build[combinedIndex] = sortedArmyBuilding[leftIndex];
				combinedIndex++;
				leftIndex++;
			}
		}

		for (int i = left; i <= right; i++) {
			sortedArmyBuilding[i] = army_build[i];
		}
	}

	public final void createProduceArmyBuilding(Group currentGroup) {
		int i, j = 0;
		Building[] build = currentGroup.getBuilding();
		Coordinate origin = currentGroup.getHQBuilding().getCoordinate();
		for (i = 0; i < DEFAULT_MAX_BUILDING_PER_GROUP; i++) {
			if (build[i] != null) {
				if (build[i].getBuildingType() == PRODUCE_ARMY_TYPE) {
					j++;
				}
			}
		}
		if (j > 0) {
			Army_Building[] armyBuilding = new Army_Building[j];
			j = 0;
			for (i = 0; i < DEFAULT_MAX_BUILDING_PER_GROUP; i++) {
				if (build[i] != null) {
					if (build[i].getBuildingType() == PRODUCE_ARMY_TYPE) {
						armyBuilding[j] = (Army_Building) build[i];
						armyBuilding[j].setDistance(armyBuilding[j]
								.getCoordinate().getDistance(origin));
						j++;
					}
				}
			}
			setSortedArmyBuilding(armyBuilding);
		}
	}

	public final void generateMove(Army arm, int initialPoint) {
		initializeAlternativePath();
		if (arm != null) {
			map.setMovementSet();
			if (arm.getUnitType() == (LAND_TYPE + SEA_TYPE)) {
				move_and_surf(arm, initialPoint);
			} else if (arm.getUnitType() == LAND_TYPE
					|| arm.getUnitType() == SEA_TYPE) {
				move(arm, initialPoint);
			} else {// this.getUnitType() == AIR_TYPE
				fly(arm, initialPoint);
			}
		}
	}

	public final void move_and_surf(Army arm, int initialPoint) {
		MovementSet[][] moveSet = map.getMovementSet();

		int movement;
		int locationX = arm.getLocationX();
		int locationY = arm.getLocationY();

		moveSet[locationY][locationX] = new MovementSet(locationX, locationY);
		moveSet[locationY][locationX].setPoint(initialPoint);

		movement = arm.getTotalMovement();
		moveToTheLeft(locationX, locationY, movement, moveSet, arm);
		moveToTheRight(locationX, locationY, movement, moveSet, arm);
		moveToTheTop(locationX, locationY, movement, moveSet, arm);
		moveToTheBottom(locationX, locationY, movement, moveSet, arm);

	}

	public final void move(Army arm, int initialPoint) {
		MovementSet[][] moveSet = map.getMovementSet();

		int movement;
		int locationX = arm.getLocationX();
		int locationY = arm.getLocationY();

		moveSet[locationY][locationX] = new MovementSet(locationX, locationY);
		moveSet[locationY][locationX].setPoint(initialPoint);

		movement = arm.getTotalMovement();
		toTheLeft(locationX, locationY, movement, moveSet, arm);
		toTheRight(locationX, locationY, movement, moveSet, arm);
		toTheTop(locationX, locationY, movement, moveSet, arm);
		toTheBottom(locationX, locationY, movement, moveSet, arm);
	}

	public final void toTheLeft(int x, int y, int moveLeft,
			MovementSet[][] moveSet, Army arm) {
		int total;
		int diff;
		int category;

		total = x - 1;
		if (total > -1) {
			if (map.getArmy(total, y) == null) {
				if (moveSet[y][total] == null) {
					diff = moveLeft
							- map.getEnvironment(total, y).getObstaclePoint()
							- 1;
					category = map.getEnvironment(total, y).getCategory();
					if (diff > -1
							&& (((arm.getUnitType() == category)) || (category == (LAND_TYPE + SEA_TYPE)))) {
						moveSet[y][total] = new MovementSet(x, y);
						moveSet[y][total].setMovementLeft(diff);
						if (diff != 0) {
							changeMovementLeft(total, y, LEFT_DIRECTION, diff,
									moveSet, arm);
						}
					}
				} else if (moveSet[y][total].getMovementLeft() < moveLeft) {
					diff = moveLeft
							- map.getEnvironment(total, y).getObstaclePoint()
							- 1;
					category = map.getEnvironment(total, y).getCategory();
					if (diff > -1 && (((arm.getUnitType() == category)))
							|| (category == (LAND_TYPE + SEA_TYPE))) {
						moveSet[y][total].setMovementLeft(diff);
						if (diff != 0) {
							changeMovementLeft(total, y, LEFT_DIRECTION, diff,
									moveSet, arm);
						}
					}
				}
			} else if (getGroup(map.getArmy(total, y).getGroupID()).getSide() == getGroup(
					arm.getGroupID()).getSide()) {
				diff = moveLeft
						- map.getEnvironment(total, y).getObstaclePoint() - 1;
				alternativePath.add(new AlternativeCoordinate(new Coordinate(x,
						y), new Coordinate(total, y)));
				category = map.getEnvironment(total, y).getCategory();
				if (diff > 0
						&& (((arm.getUnitType() == category)) || (category == (LAND_TYPE + SEA_TYPE)))) {
					changeMovementLeft(total, y, LEFT_DIRECTION, diff, moveSet,
							arm);
				}
			}
		}
	}

	public final void toTheRight(int x, int y, int moveLeft,
			MovementSet[][] moveSet, Army arm) {
		int total;
		int diff;
		int category;

		total = x + 1;
		if (total < map.getNumberOfColumn()) {
			if (map.getArmy(total, y) == null) {
				if (moveSet[y][total] == null) {
					diff = moveLeft
							- map.getEnvironment(total, y).getObstaclePoint()
							- 1;
					category = map.getEnvironment(total, y).getCategory();
					if (diff > -1
							&& (((arm.getUnitType() == category)) || (category == (LAND_TYPE + SEA_TYPE)))) {
						moveSet[y][total] = new MovementSet(x, y);
						moveSet[y][total].setMovementLeft(diff);
						if (diff != 0) {
							changeMovementLeft(total, y, RIGHT_DIRECTION, diff,
									moveSet, arm);
						}
					}
				} else if (moveSet[y][total].getMovementLeft() < moveLeft) {
					diff = moveLeft
							- map.getEnvironment(total, y).getObstaclePoint()
							- 1;
					category = map.getEnvironment(total, y).getCategory();
					if (diff > -1
							&& (((arm.getUnitType() == category)) || (category == (LAND_TYPE + SEA_TYPE)))) {
						moveSet[y][total].setMovementLeft(diff);
						if (diff != 0) {
							changeMovementLeft(total, y, RIGHT_DIRECTION, diff,
									moveSet, arm);
						}
					}
				}
			} else if (getGroup(map.getArmy(total, y).getGroupID()).getSide() == getGroup(
					arm.getGroupID()).getSide()) {
				diff = moveLeft
						- map.getEnvironment(total, y).getObstaclePoint() - 1;
				alternativePath.add(new AlternativeCoordinate(new Coordinate(x,
						y), new Coordinate(total, y)));
				category = map.getEnvironment(total, y).getCategory();
				if (diff > 0
						&& (((arm.getUnitType() == category)) || (category == (LAND_TYPE + SEA_TYPE)))) {
					changeMovementLeft(total, y, RIGHT_DIRECTION, diff,
							moveSet, arm);
				}
			}
		}
	}

	public final void toTheTop(int x, int y, int moveLeft,
			MovementSet[][] moveSet, Army arm) {
		int total;
		int diff;
		int category;

		total = y - 1;
		if (total > -1) {
			if (map.getArmy(x, total) == null) {
				if (moveSet[total][x] == null) {
					diff = moveLeft
							- map.getEnvironment(x, total).getObstaclePoint()
							- 1;
					category = map.getEnvironment(x, total).getCategory();
					if (diff > -1
							&& (((arm.getUnitType() == category)) || (category == (LAND_TYPE + SEA_TYPE)))) {
						moveSet[total][x] = new MovementSet(x, y);
						moveSet[total][x].setMovementLeft(diff);
						if (diff != 0) {
							changeMovementLeft(x, total, TOP_DIRECTION, diff,
									moveSet, arm);
						}
					}
				} else if (moveSet[total][x].getMovementLeft() < moveLeft) {
					diff = moveLeft
							- map.getEnvironment(x, total).getObstaclePoint()
							- 1;
					category = map.getEnvironment(x, total).getCategory();
					if (diff > -1
							&& (((arm.getUnitType() == category)) || (category == (LAND_TYPE + SEA_TYPE)))) {
						moveSet[total][x].setMovementLeft(diff);
						if (diff != 0) {
							changeMovementLeft(x, total, TOP_DIRECTION, diff,
									moveSet, arm);
						}
					}
				}
			} else if (getGroup(map.getArmy(x, total).getGroupID()).getSide() == getGroup(
					arm.getGroupID()).getSide()) {
				diff = moveLeft
						- map.getEnvironment(x, total).getObstaclePoint() - 1;
				alternativePath.add(new AlternativeCoordinate(new Coordinate(x,
						y), new Coordinate(x, total)));
				category = map.getEnvironment(x, total).getCategory();
				if (diff > 0
						&& (((arm.getUnitType() == category)) || (category == (LAND_TYPE + SEA_TYPE)))) {
					changeMovementLeft(x, total, TOP_DIRECTION, diff, moveSet,
							arm);
				}
			}
		}
	}

	public final void toTheBottom(int x, int y, int moveLeft,
			MovementSet[][] moveSet, Army arm) {
		int total;
		int diff;
		int category;

		total = y + 1;
		if (total < map.getNumberOfRow()) {
			if (map.getArmy(x, total) == null) {
				if (moveSet[total][x] == null) {
					diff = moveLeft
							- map.getEnvironment(x, total).getObstaclePoint()
							- 1;
					category = map.getEnvironment(x, total).getCategory();
					if (diff > -1
							&& (((arm.getUnitType() == category)) || (category == (LAND_TYPE + SEA_TYPE)))) {
						moveSet[total][x] = new MovementSet(x, y);
						moveSet[total][x].setMovementLeft(diff);
						if (diff != 0) {
							changeMovementLeft(x, total, BOTTOM_DIRECTION,
									diff, moveSet, arm);
						}
					}
				} else if (moveSet[total][x].getMovementLeft() < moveLeft) {
					diff = moveLeft
							- map.getEnvironment(x, total).getObstaclePoint()
							- 1;
					category = map.getEnvironment(x, total).getCategory();
					if (diff > -1
							&& (((arm.getUnitType() == category)) || (category == (LAND_TYPE + SEA_TYPE)))) {
						moveSet[total][x].setMovementLeft(diff);
						if (diff != 0) {
							changeMovementLeft(x, total, BOTTOM_DIRECTION,
									diff, moveSet, arm);
						}
					}
				}
			} else if (getGroup(map.getArmy(x, total).getGroupID()).getSide() == getGroup(
					arm.getGroupID()).getSide()) {
				diff = moveLeft
						- map.getEnvironment(x, total).getObstaclePoint() - 1;
				alternativePath.add(new AlternativeCoordinate(new Coordinate(x,
						y), new Coordinate(x, total)));
				category = map.getEnvironment(x, total).getCategory();
				if (diff > 0
						&& (((arm.getUnitType() == category)) || (category == (LAND_TYPE + SEA_TYPE)))) {
					changeMovementLeft(x, total, BOTTOM_DIRECTION, diff,
							moveSet, arm);
				}
			}
		}
	}

	public final void moveToTheLeft(int x, int y, int moveLeft,
			MovementSet[][] moveSet, Army arm) {
		int total;
		int diff;

		total = x - 1;
		if (total > -1) {
			if (map.getArmy(total, y) == null) {
				if (moveSet[y][total] == null) {
					diff = moveLeft
							- map.getEnvironment(total, y).getObstaclePoint()
							- 1;
					if (diff > -1) {
						moveSet[y][total] = new MovementSet(x, y);
						moveSet[y][total].setMovementLeft(diff);
						if (diff != 0) {
							changeMovementLeft_on_sea_land(total, y,
									LEFT_DIRECTION, diff, moveSet, arm);
						}
					}
				} else if (moveSet[y][total].getMovementLeft() < moveLeft) {
					diff = moveLeft
							- map.getEnvironment(total, y).getObstaclePoint()
							- 1;
					if (diff > -1) {
						moveSet[y][total].setMovementLeft(diff);
						if (diff != 0) {
							changeMovementLeft_on_sea_land(total, y,
									LEFT_DIRECTION, diff, moveSet, arm);
						}
					}
				}
			} else if (getGroup(map.getArmy(total, y).getGroupID()).getSide() == getGroup(
					arm.getGroupID()).getSide()) {
				diff = moveLeft
						- map.getEnvironment(total, y).getObstaclePoint() - 1;
				alternativePath.add(new AlternativeCoordinate(new Coordinate(x,
						y), new Coordinate(total, y)));
				if (diff > 0) {
					changeMovementLeft_on_sea_land(total, y, LEFT_DIRECTION,
							diff, moveSet, arm);
				}
			}
		}
	}

	public final void moveToTheRight(int x, int y, int moveLeft,
			MovementSet[][] moveSet, Army arm) {
		int total;
		int diff;

		total = x + 1;
		if (total < map.getNumberOfColumn()) {
			if (map.getArmy(total, y) == null) {
				if (moveSet[y][total] == null) {
					diff = moveLeft
							- map.getEnvironment(total, y).getObstaclePoint()
							- 1;
					if (diff > -1) {
						moveSet[y][total] = new MovementSet(x, y);
						moveSet[y][total].setMovementLeft(diff);
						if (diff != 0) {
							changeMovementLeft_on_sea_land(total, y,
									RIGHT_DIRECTION, diff, moveSet, arm);
						}
					}
				} else if (moveSet[y][total].getMovementLeft() < moveLeft) {
					diff = moveLeft
							- map.getEnvironment(total, y).getObstaclePoint()
							- 1;
					if (diff > -1) {
						moveSet[y][total].setMovementLeft(diff);
						if (diff != 0) {
							changeMovementLeft_on_sea_land(total, y,
									RIGHT_DIRECTION, diff, moveSet, arm);
						}
					}
				}
			} else if (getGroup(map.getArmy(total, y).getGroupID()).getSide() == getGroup(
					arm.getGroupID()).getSide()) {
				diff = moveLeft
						- map.getEnvironment(total, y).getObstaclePoint() - 1;
				alternativePath.add(new AlternativeCoordinate(new Coordinate(x,
						y), new Coordinate(total, y)));
				if (diff > 0) {
					changeMovementLeft_on_sea_land(total, y, RIGHT_DIRECTION,
							diff, moveSet, arm);
				}
			}
		}
	}

	public final void moveToTheTop(int x, int y, int moveLeft,
			MovementSet[][] moveSet, Army arm) {
		int total;
		int diff;

		total = y - 1;
		if (total > -1) {
			if (map.getArmy(x, total) == null) {
				if (moveSet[total][x] == null) {
					diff = moveLeft
							- map.getEnvironment(x, total).getObstaclePoint()
							- 1;
					if (diff > -1) {
						moveSet[total][x] = new MovementSet(x, y);
						moveSet[total][x].setMovementLeft(diff);
						if (diff != 0) {
							changeMovementLeft_on_sea_land(x, total,
									TOP_DIRECTION, diff, moveSet, arm);
						}
					}
				} else if (moveSet[total][x].getMovementLeft() < moveLeft) {
					diff = moveLeft
							- map.getEnvironment(x, total).getObstaclePoint()
							- 1;
					if (diff > -1) {
						moveSet[total][x].setMovementLeft(diff);
						if (diff != 0) {
							changeMovementLeft_on_sea_land(x, total,
									TOP_DIRECTION, diff, moveSet, arm);
						}
					}
				}
			} else if (getGroup(map.getArmy(x, total).getGroupID()).getSide() == getGroup(
					arm.getGroupID()).getSide()) {
				diff = moveLeft
						- map.getEnvironment(x, total).getObstaclePoint() - 1;
				alternativePath.add(new AlternativeCoordinate(new Coordinate(x,
						y), new Coordinate(x, total)));
				if (diff > 0) {
					changeMovementLeft_on_sea_land(x, total, TOP_DIRECTION,
							diff, moveSet, arm);
				}
			}
		}
	}

	public final void moveToTheBottom(int x, int y, int moveLeft,
			MovementSet[][] moveSet, Army arm) {
		int total;
		int diff;

		total = y + 1;
		if (total < map.getNumberOfRow()) {
			if (map.getArmy(x, total) == null) {
				if (moveSet[total][x] == null) {
					diff = moveLeft
							- map.getEnvironment(x, total).getObstaclePoint()
							- 1;
					if (diff > -1) {
						moveSet[total][x] = new MovementSet(x, y);
						moveSet[total][x].setMovementLeft(diff);
						if (diff != 0) {
							changeMovementLeft_on_sea_land(x, total,
									BOTTOM_DIRECTION, diff, moveSet, arm);
						}
					}
				} else if (moveSet[total][x].getMovementLeft() < moveLeft) {
					diff = moveLeft
							- map.getEnvironment(x, total).getObstaclePoint()
							- 1;
					if (diff > -1) {
						moveSet[total][x].setMovementLeft(diff);
						if (diff != 0) {
							changeMovementLeft_on_sea_land(x, total,
									BOTTOM_DIRECTION, diff, moveSet, arm);
						}
					}
				}
			} else if (getGroup(map.getArmy(x, total).getGroupID()).getSide() == getGroup(
					arm.getGroupID()).getSide()) {
				diff = moveLeft
						- map.getEnvironment(x, total).getObstaclePoint() - 1;
				alternativePath.add(new AlternativeCoordinate(new Coordinate(x,
						y), new Coordinate(x, total)));
				if (diff > 0) {
					changeMovementLeft_on_sea_land(x, total, BOTTOM_DIRECTION,
							diff, moveSet, arm);
				}
			}
		}
	}

	public final void changeMovementLeft_on_sea_land(int x, int y,
			int direction, int moveLeft, MovementSet[][] moveSet, Army arm) {
		switch (direction) {
		case TOP_DIRECTION:
			moveToTheLeft(x, y, moveLeft, moveSet, arm);
			moveToTheRight(x, y, moveLeft, moveSet, arm);
			moveToTheTop(x, y, moveLeft, moveSet, arm);
			break;
		case RIGHT_DIRECTION:
			moveToTheTop(x, y, moveLeft, moveSet, arm);
			moveToTheBottom(x, y, moveLeft, moveSet, arm);
			moveToTheRight(x, y, moveLeft, moveSet, arm);
			break;
		case BOTTOM_DIRECTION:
			moveToTheLeft(x, y, moveLeft, moveSet, arm);
			moveToTheRight(x, y, moveLeft, moveSet, arm);
			moveToTheBottom(x, y, moveLeft, moveSet, arm);
			break;
		case LEFT_DIRECTION:
			moveToTheTop(x, y, moveLeft, moveSet, arm);
			moveToTheBottom(x, y, moveLeft, moveSet, arm);
			moveToTheLeft(x, y, moveLeft, moveSet, arm);
			break;
		}
	}

	public final void changeMovementLeft(int x, int y, int direction,
			int moveLeft, MovementSet[][] moveSet, Army arm) {
		switch (direction) {
		case TOP_DIRECTION:
			toTheRight(x, y, moveLeft, moveSet, arm);
			toTheLeft(x, y, moveLeft, moveSet, arm);
			toTheTop(x, y, moveLeft, moveSet, arm);
			break;
		case RIGHT_DIRECTION:
			toTheTop(x, y, moveLeft, moveSet, arm);
			toTheBottom(x, y, moveLeft, moveSet, arm);
			toTheRight(x, y, moveLeft, moveSet, arm);
			break;
		case BOTTOM_DIRECTION:
			toTheRight(x, y, moveLeft, moveSet, arm);
			toTheLeft(x, y, moveLeft, moveSet, arm);
			toTheBottom(x, y, moveLeft, moveSet, arm);
			break;
		case LEFT_DIRECTION:
			toTheTop(x, y, moveLeft, moveSet, arm);
			toTheBottom(x, y, moveLeft, moveSet, arm);
			toTheLeft(x, y, moveLeft, moveSet, arm);
			break;
		}
	}

	public final void changeMovementLeft_on_fly(int x, int y, int direction,
			int moveLeft, MovementSet[][] moveSet, Army arm) {
		switch (direction) {
		case TOP_DIRECTION:
			flyToTheRight(x, y, moveLeft, moveSet, arm);
			flyToTheLeft(x, y, moveLeft, moveSet, arm);
			flyToTheTop(x, y, moveLeft, moveSet, arm);
			break;
		case RIGHT_DIRECTION:
			flyToTheTop(x, y, moveLeft, moveSet, arm);
			flyToTheBottom(x, y, moveLeft, moveSet, arm);
			flyToTheRight(x, y, moveLeft, moveSet, arm);
			break;
		case BOTTOM_DIRECTION:
			flyToTheRight(x, y, moveLeft, moveSet, arm);
			flyToTheLeft(x, y, moveLeft, moveSet, arm);
			flyToTheBottom(x, y, moveLeft, moveSet, arm);
			break;
		case LEFT_DIRECTION:
			flyToTheTop(x, y, moveLeft, moveSet, arm);
			flyToTheBottom(x, y, moveLeft, moveSet, arm);
			flyToTheLeft(x, y, moveLeft, moveSet, arm);
			break;
		}
	}

	public final void flyToTheLeft(int x, int y, int moveLeft,
			MovementSet[][] moveSet, Army arm) {
		int total;
		int diff;

		total = x - 1;
		if (total > -1) {
			if (map.getArmy(total, y) == null) {
				if (moveSet[y][total] == null) {
					diff = moveLeft - 1;
					if (diff > -1) {
						moveSet[y][total] = new MovementSet(x, y);
						moveSet[y][total].setMovementLeft(diff);
						if (diff != 0) {
							changeMovementLeft_on_fly(total, y, LEFT_DIRECTION,
									diff, moveSet, arm);
						}
					}
				} else if (moveSet[y][total].getMovementLeft() < moveLeft) {
					diff = moveLeft - 1;
					if (diff > -1) {
						moveSet[y][total].setMovementLeft(diff);
						if (diff != 0) {
							changeMovementLeft_on_fly(total, y, LEFT_DIRECTION,
									diff, moveSet, arm);
						}
					}
				}
			} else {
				diff = moveLeft - 1;
				alternativePath.add(new AlternativeCoordinate(new Coordinate(x,
						y), new Coordinate(total, y)));
				if (diff > 0) {
					changeMovementLeft_on_fly(total, y, LEFT_DIRECTION, diff,
							moveSet, arm);
				}
			}
		}
	}

	public final void flyToTheRight(int x, int y, int moveLeft,
			MovementSet[][] moveSet, Army arm) {
		int total;
		int diff;

		total = x + 1;
		if (total < map.getNumberOfColumn()) {
			if (map.getArmy(total, y) == null) {
				if (moveSet[y][total] == null) {
					diff = moveLeft - 1;
					if (diff > -1) {
						moveSet[y][total] = new MovementSet(x, y);
						moveSet[y][total].setMovementLeft(diff);
						if (diff != 0) {
							changeMovementLeft_on_fly(total, y,
									RIGHT_DIRECTION, diff, moveSet, arm);
						}
					}
				} else if (moveSet[y][total].getMovementLeft() < moveLeft) {
					diff = moveLeft - 1;
					if (diff > -1) {
						moveSet[y][total].setMovementLeft(diff);
						if (diff != 0) {
							changeMovementLeft_on_fly(total, y,
									RIGHT_DIRECTION, diff, moveSet, arm);
						}
					}
				}
			} else {
				diff = moveLeft - 1;
				alternativePath.add(new AlternativeCoordinate(new Coordinate(x,
						y), new Coordinate(total, y)));
				if (diff > 0) {
					changeMovementLeft_on_fly(total, y, RIGHT_DIRECTION, diff,
							moveSet, arm);
				}
			}
		}
	}

	public final void flyToTheTop(int x, int y, int moveLeft,
			MovementSet[][] moveSet, Army arm) {
		int total;
		int diff;

		total = y - 1;
		if (total > -1) {
			if (map.getArmy(x, total) == null) {
				if (moveSet[total][x] == null) {
					diff = moveLeft - 1;
					if (diff > -1) {
						moveSet[total][x] = new MovementSet(x, y);
						moveSet[total][x].setMovementLeft(diff);
						if (diff != 0) {
							changeMovementLeft_on_fly(x, total, TOP_DIRECTION,
									diff, moveSet, arm);
						}
					}
				} else if (moveSet[total][x].getMovementLeft() < moveLeft) {
					diff = moveLeft - 1;
					if (diff > -1) {
						moveSet[total][x].setMovementLeft(diff);
						if (diff != 0) {
							changeMovementLeft_on_fly(x, total, TOP_DIRECTION,
									diff, moveSet, arm);
						}
					}
				}
			} else {
				diff = moveLeft - 1;
				alternativePath.add(new AlternativeCoordinate(new Coordinate(x,
						y), new Coordinate(x, total)));
				if (diff > 0) {
					changeMovementLeft_on_fly(x, total, TOP_DIRECTION, diff,
							moveSet, arm);
				}
			}
		}
	}

	public final void flyToTheBottom(int x, int y, int moveLeft,
			MovementSet[][] moveSet, Army arm) {
		int total;
		int diff;

		total = y + 1;
		if (total < map.getNumberOfRow()) {
			if (map.getArmy(x, total) == null) {
				if (moveSet[total][x] == null) {
					diff = moveLeft - 1;
					if (diff > -1) {
						moveSet[total][x] = new MovementSet(x, y);
						moveSet[total][x].setMovementLeft(diff);
						if (diff != 0) {
							changeMovementLeft_on_fly(x, total,
									BOTTOM_DIRECTION, diff, moveSet, arm);
						}
					}
				} else if (moveSet[total][x].getMovementLeft() < moveLeft) {
					diff = moveLeft - 1;
					if (diff > -1) {
						moveSet[total][x].setMovementLeft(diff);
						if (diff != 0) {
							changeMovementLeft_on_fly(x, total,
									BOTTOM_DIRECTION, diff, moveSet, arm);
						}
					}
				}
			} else {
				diff = moveLeft - 1;
				alternativePath.add(new AlternativeCoordinate(new Coordinate(x,
						y), new Coordinate(x, total)));
				if (diff > 0) {
					changeMovementLeft_on_fly(x, total, BOTTOM_DIRECTION, diff,
							moveSet, arm);
				}
			}
		}
	}

	public final void fly(Army arm, int initialPoint) {
		MovementSet[][] moveSet = map.getMovementSet();

		int movement;
		int locationX = arm.getLocationX();
		int locationY = arm.getLocationY();

		moveSet[locationY][locationX] = new MovementSet(locationX, locationY);
		moveSet[locationY][locationX].setPoint(initialPoint);

		movement = arm.getTotalMovement();
		flyToTheLeft(locationX, locationY, movement, moveSet, arm);
		flyToTheRight(locationX, locationY, movement, moveSet, arm);
		flyToTheTop(locationX, locationY, movement, moveSet, arm);
		flyToTheBottom(locationX, locationY, movement, moveSet, arm);

	}

	public final void generateAttackSet(MovementSet movementSet, Army arm,
			int locationX, int locationY) {
		int range = arm.getTotalAttackRange() + 1;

		int side = getGroup(arm.getGroupID()).getSide();
		int row = map.getNumberOfRow();
		int column = map.getNumberOfColumn();
		int i, j, total, diff, subTotal;

		movementSet.setAttackSet();

		for (i = 1; i < range; i++) {
			total = locationX + i;
			if ((total) < column) {
				if (map.getArmy(total, locationY) != null) {
					if (getGroup(map.getArmy(total, locationY).getGroupID())
							.getSide() != side) {
						movementSet.addAttackItem(total, locationY);
					}
				}
			}

			total = locationX - i;
			if ((total) > -1) {
				if (map.getArmy(total, locationY) != null) {
					if (getGroup(map.getArmy(total, locationY).getGroupID())
							.getSide() != side) {
						movementSet.addAttackItem(total, locationY);
					}
				}
			}

			total = locationY + i;
			if ((total) < row) {
				if (map.getArmy(locationX, total) != null) {
					if (getGroup(map.getArmy(locationX, total).getGroupID())
							.getSide() != side) {
						movementSet.addAttackItem(locationX, total);
					}
				}

				diff = range - i;

				for (j = 1; j < diff; j++) {
					subTotal = locationX + j;
					if (subTotal < column) {
						if (map.getArmy(subTotal, total) != null) {
							if (getGroup(
									map.getArmy(subTotal, total).getGroupID())
									.getSide() != side) {
								movementSet.addAttackItem(subTotal, total);
							}
						}
					}
					subTotal = locationX - j;
					if (subTotal > -1) {
						if (map.getArmy(subTotal, total) != null) {
							if (getGroup(
									map.getArmy(subTotal, total).getGroupID())
									.getSide() != side) {
								movementSet.addAttackItem(subTotal, total);
							}
						}
					}
				}
			}

			total = locationY - i;
			if ((total) > -1) {
				if (map.getArmy(locationX, total) != null) {
					if (getGroup(map.getArmy(locationX, total).getGroupID())
							.getSide() != side) {
						movementSet.addAttackItem(locationX, total);
					}
				}

				diff = range - i;

				for (j = 1; j < diff; j++) {
					subTotal = locationX + j;
					if (subTotal < column) {
						if (map.getArmy(subTotal, total) != null) {
							if (getGroup(
									map.getArmy(subTotal, total).getGroupID())
									.getSide() != side) {
								movementSet.addAttackItem(subTotal, total);
							}
						}
					}
					subTotal = locationX - j;
					if (subTotal > -1) {
						if (map.getArmy(subTotal, total) != null) {
							if (getGroup(
									map.getArmy(subTotal, total).getGroupID())
									.getSide() != side) {
								movementSet.addAttackItem(subTotal, total);
							}
						}
					}
				}
			}
		}
	}

	public final void generateAndEvaluateOccupySet(MovementSet movementSet,
			Army arm, int locationX, int locationY) {

		Building build = map.getBuilding(locationX, locationY);
		if (build != null) {
			if (build.getGroupID() != DEFAULT_MAX_GROUP) {
				if (group[build.getGroupID()].getSide() != group[arm
						.getGroupID()].getSide()) {
					Ability temp = arm.getOccupyAbility();
					temp.setTarget(new Coordinate(locationX, locationY));
					switch (build.getBuildingType()) {
					case UNKNOWN_TYPE:
						temp.abilityManager(arm, this, true);
						break;
					case PRODUCE_GOLD_TYPE:
						temp.abilityManager(arm, this, true);
						break;
					case RESTORE_HP_TYPE:
						temp.abilityManager(arm, this, true);
						break;
					case PRODUCE_ARMY_TYPE:
						temp.abilityManager(arm, this, true);
						break;
					case HEAD_QUARTER_TYPE:
						if (((HQ_Building) build).getTurnsBeforeLost() != MANY_TURNS) {
							temp.setTarget(null);
							temp.setAbilityPoint(0);
							movementSet.setOccupySet(null);
							return;
						} else {
							temp.abilityManager(arm, this, true);
						}
						break;
					}
					movementSet.setOccupySet(locationX, locationY,
							temp.getAbilityPoint());
				} else if (build.getBuildingType() == HEAD_QUARTER_TYPE) {
					if (((HQ_Building) build).getTurnsBeforeLost() != MANY_TURNS) {
						Ability temp = arm.getOccupyAbility();
						temp.setTarget(new Coordinate(locationX, locationY));
						temp.abilityManager(arm, this, true);
						movementSet.setOccupySet(locationX, locationY,
								temp.getAbilityPoint());
					}
				}
			} else {
				Ability temp = arm.getOccupyAbility();
				temp.setTarget(new Coordinate(locationX, locationY));
				switch (build.getBuildingType()) {
				case UNKNOWN_TYPE:
					temp.abilityManager(arm, this, true);
					break;
				case PRODUCE_GOLD_TYPE:
					temp.abilityManager(arm, this, true);
					break;
				case RESTORE_HP_TYPE:
					temp.abilityManager(arm, this, true);
					break;
				case PRODUCE_ARMY_TYPE:
					temp.abilityManager(arm, this, true);
					break;
				}
				movementSet.setOccupySet(locationX, locationY,
						temp.getAbilityPoint());
			}
		}
	}

	public final void generateAbilitySet(MovementSet movementSet, Army arm,
			int locationX, int locationY) {
		Ability[] ability = arm.getAbility(arm.getLevel());

		int side = getGroup(arm.getGroupID()).getSide();
		int row = map.getNumberOfRow();
		int column = map.getNumberOfColumn();
		int i, j, total, diff, subTotal;
		movementSet.setAbilitySet();
		for (int p = 0; p < ability.length; p++) {
			if (ability[p].getID() != NO_SKILL) {
				int range = ability[p].getAbilityRange() + 1;

				if (ability[p].getAbilityAffectTo() == AFFECT_ALLY
						|| ability[p].getAbilityAffectTo() == AFFECT_BOTH) {
					Ability temp = Ability.abilityInitializer(ability[p]);
					temp.setTarget(new Coordinate(movementSet.getLocationX(),
							movementSet.getLocationY()));
					movementSet.addAbilityItem(temp);
				} else if (ability[p].getAbilityAffectTo() == AFFECT_SELF) {
					Ability temp = Ability.abilityInitializer(ability[p]);
					temp.setTarget(new Coordinate(movementSet.getLocationX(),
							movementSet.getLocationY()));
					movementSet.addAbilityItem(temp);
					return;
				}

				for (i = 1; i < range; i++) {
					total = locationX + i;
					if ((total) < column) {
						if (map.getArmy(total, locationY) != null) {
							if (ability[p].getAbilityAffectTo() == AFFECT_ENEMY) {
								if (getGroup(
										map.getArmy(total, locationY)
												.getGroupID()).getSide() != side) {
									Ability temp = Ability
											.abilityInitializer(ability[p]);
									temp.setTarget(new Coordinate(total,
											locationY));
									movementSet.addAbilityItem(temp);
								}
							} else if (ability[p].getAbilityAffectTo() == AFFECT_ALLY) {
								if (getGroup(
										map.getArmy(total, locationY)
												.getGroupID()).getSide() == side) {
									Ability temp = Ability
											.abilityInitializer(ability[p]);
									temp.setTarget(new Coordinate(total,
											locationY));
									movementSet.addAbilityItem(temp);
								}
							} else {
								Ability temp = Ability
										.abilityInitializer(ability[p]);
								temp.setTarget(new Coordinate(total, locationY));
								movementSet.addAbilityItem(temp);
							}
						}
					}

					total = locationX - i;
					if ((total) > -1) {
						if (map.getArmy(total, locationY) != null) {
							if (ability[p].getAbilityAffectTo() == AFFECT_ENEMY) {
								if (getGroup(
										map.getArmy(total, locationY)
												.getGroupID()).getSide() != side) {
									Ability temp = Ability
											.abilityInitializer(ability[p]);
									temp.setTarget(new Coordinate(total,
											locationY));
									movementSet.addAbilityItem(temp);
								}
							} else if (ability[p].getAbilityAffectTo() == AFFECT_ALLY) {
								if (getGroup(
										map.getArmy(total, locationY)
												.getGroupID()).getSide() == side) {
									Ability temp = Ability
											.abilityInitializer(ability[p]);
									temp.setTarget(new Coordinate(total,
											locationY));
									movementSet.addAbilityItem(temp);
								}
							} else {
								Ability temp = Ability
										.abilityInitializer(ability[p]);
								temp.setTarget(new Coordinate(total, locationY));
								movementSet.addAbilityItem(temp);
							}
						}
					}

					total = locationY + i;
					if ((total) < row) {
						if (map.getArmy(locationX, total) != null) {
							if (ability[p].getAbilityAffectTo() == AFFECT_ENEMY) {
								if (getGroup(
										map.getArmy(locationX, total)
												.getGroupID()).getSide() != side) {
									Ability temp = Ability
											.abilityInitializer(ability[p]);
									temp.setTarget(new Coordinate(locationX,
											total));
									movementSet.addAbilityItem(temp);
								}
							} else if (ability[p].getAbilityAffectTo() == AFFECT_ALLY) {
								if (getGroup(
										map.getArmy(locationX, total)
												.getGroupID()).getSide() == side) {
									Ability temp = Ability
											.abilityInitializer(ability[p]);
									temp.setTarget(new Coordinate(locationX,
											total));
									movementSet.addAbilityItem(temp);
								}
							} else {
								Ability temp = Ability
										.abilityInitializer(ability[p]);
								temp.setTarget(new Coordinate(locationX, total));
								movementSet.addAbilityItem(temp);
							}
						}

						diff = range - i;

						for (j = 1; j < diff; j++) {
							subTotal = locationX + j;
							if (subTotal < column) {
								if (map.getArmy(subTotal, total) != null) {
									if (ability[p].getAbilityAffectTo() == AFFECT_ENEMY) {
										if (getGroup(
												map.getArmy(subTotal, total)
														.getGroupID())
												.getSide() != side) {
											Ability temp = Ability
													.abilityInitializer(ability[p]);
											temp.setTarget(new Coordinate(
													subTotal, total));
											movementSet.addAbilityItem(temp);
										}
									} else if (ability[p].getAbilityAffectTo() == AFFECT_ALLY) {
										if (getGroup(
												map.getArmy(subTotal, total)
														.getGroupID())
												.getSide() == side) {
											Ability temp = Ability
													.abilityInitializer(ability[p]);
											temp.setTarget(new Coordinate(
													subTotal, total));
											movementSet.addAbilityItem(temp);
										}
									} else {
										Ability temp = Ability
												.abilityInitializer(ability[p]);
										temp.setTarget(new Coordinate(subTotal,
												total));
										movementSet.addAbilityItem(temp);
									}
								}
							}
							subTotal = locationX - j;
							if (subTotal > -1) {
								if (map.getArmy(subTotal, total) != null) {
									if (ability[p].getAbilityAffectTo() == AFFECT_ENEMY) {
										if (getGroup(
												map.getArmy(subTotal, total)
														.getGroupID())
												.getSide() != side) {
											Ability temp = Ability
													.abilityInitializer(ability[p]);
											temp.setTarget(new Coordinate(
													subTotal, total));
											movementSet.addAbilityItem(temp);
										}
									} else if (ability[p].getAbilityAffectTo() == AFFECT_ALLY) {
										if (getGroup(
												map.getArmy(subTotal, total)
														.getGroupID())
												.getSide() == side) {
											Ability temp = Ability
													.abilityInitializer(ability[p]);
											temp.setTarget(new Coordinate(
													subTotal, total));
											movementSet.addAbilityItem(temp);
										}
									} else {
										Ability temp = Ability
												.abilityInitializer(ability[p]);
										temp.setTarget(new Coordinate(subTotal,
												total));
										movementSet.addAbilityItem(temp);
									}
								}
							}
						}
					}

					total = locationY - i;
					if ((total) > -1) {
						if (map.getArmy(locationX, total) != null) {
							if (ability[p].getAbilityAffectTo() == AFFECT_ENEMY) {
								if (getGroup(
										map.getArmy(locationX, total)
												.getGroupID()).getSide() != side) {
									Ability temp = Ability
											.abilityInitializer(ability[p]);
									temp.setTarget(new Coordinate(locationX,
											total));
									movementSet.addAbilityItem(temp);
								}
							} else if (ability[p].getAbilityAffectTo() == AFFECT_ALLY) {
								if (getGroup(
										map.getArmy(locationX, total)
												.getGroupID()).getSide() == side) {
									Ability temp = Ability
											.abilityInitializer(ability[p]);
									temp.setTarget(new Coordinate(locationX,
											total));
									movementSet.addAbilityItem(temp);
								}
							} else {
								Ability temp = Ability
										.abilityInitializer(ability[p]);
								temp.setTarget(new Coordinate(locationX, total));
								movementSet.addAbilityItem(temp);
							}
						}

						diff = range - i;

						for (j = 1; j < diff; j++) {
							subTotal = locationX + j;
							if (subTotal < column) {
								if (map.getArmy(subTotal, total) != null) {
									if (ability[p].getAbilityAffectTo() == AFFECT_ENEMY) {
										if (getGroup(
												map.getArmy(subTotal, total)
														.getGroupID())
												.getSide() != side) {
											Ability temp = Ability
													.abilityInitializer(ability[p]);
											temp.setTarget(new Coordinate(
													subTotal, total));
											movementSet.addAbilityItem(temp);
										}
									} else if (ability[p].getAbilityAffectTo() == AFFECT_ALLY) {
										if (getGroup(
												map.getArmy(subTotal, total)
														.getGroupID())
												.getSide() == side) {
											Ability temp = Ability
													.abilityInitializer(ability[p]);
											temp.setTarget(new Coordinate(
													subTotal, total));
											movementSet.addAbilityItem(temp);
										}
									} else {
										Ability temp = Ability
												.abilityInitializer(ability[p]);
										temp.setTarget(new Coordinate(subTotal,
												total));
										movementSet.addAbilityItem(temp);
									}
								}
							}

							subTotal = locationX - j;
							if (subTotal > -1) {
								if (map.getArmy(subTotal, total) != null) {
									if (ability[p].getAbilityAffectTo() == AFFECT_ENEMY) {
										if (getGroup(
												map.getArmy(subTotal, total)
														.getGroupID())
												.getSide() != side) {
											Ability temp = Ability
													.abilityInitializer(ability[p]);
											temp.setTarget(new Coordinate(
													subTotal, total));
											movementSet.addAbilityItem(temp);
										}
									} else if (ability[p].getAbilityAffectTo() == AFFECT_ALLY) {
										if (getGroup(
												map.getArmy(subTotal, total)
														.getGroupID())
												.getSide() == side) {
											Ability temp = Ability
													.abilityInitializer(ability[p]);
											temp.setTarget(new Coordinate(
													subTotal, total));
											movementSet.addAbilityItem(temp);
										}
									} else {
										Ability temp = Ability
												.abilityInitializer(ability[p]);
										temp.setTarget(new Coordinate(subTotal,
												total));
										movementSet.addAbilityItem(temp);
									}
								}
							}
						}
					}
				}
			}
		}
	}

	public final void generateAbilitySet(MovementSet movementSet, Army arm,
			int locationX, int locationY, Ability ability) {

		int side = getGroup(arm.getGroupID()).getSide();
		int row = map.getNumberOfRow();
		int column = map.getNumberOfColumn();
		int i, j, total, diff, subTotal;
		movementSet.setAbilitySet();
		int range = ability.getAbilityRange() + 1;

		if (ability.getID() != NO_SKILL) {
			if (ability.getAbilityAffectTo() == AFFECT_ALLY
					|| ability.getAbilityAffectTo() == AFFECT_BOTH) {
				Ability temp = Ability.abilityInitializer(ability);
				temp.setTarget(new Coordinate(movementSet.getLocationX(),
						movementSet.getLocationY()));
				movementSet.addAbilityItem(temp);
			} else if (ability.getAbilityAffectTo() == AFFECT_SELF) {
				Ability temp = Ability.abilityInitializer(ability);
				temp.setTarget(new Coordinate(movementSet.getLocationX(),
						movementSet.getLocationY()));
				movementSet.addAbilityItem(temp);
				return;
			}

			for (i = 1; i < range; i++) {
				total = locationX + i;
				if ((total) < column) {
					if (map.getArmy(total, locationY) != null) {
						if (ability.getAbilityAffectTo() == AFFECT_ENEMY) {
							if (getGroup(
									map.getArmy(total, locationY).getGroupID())
									.getSide() != side) {
								Ability temp = Ability
										.abilityInitializer(ability);
								temp.setTarget(new Coordinate(total, locationY));
								movementSet.addAbilityItem(temp);
							}
						} else if (ability.getAbilityAffectTo() == AFFECT_ALLY) {
							if (getGroup(
									map.getArmy(total, locationY).getGroupID())
									.getSide() == side) {
								Ability temp = Ability
										.abilityInitializer(ability);
								temp.setTarget(new Coordinate(total, locationY));
								movementSet.addAbilityItem(temp);
							}
						} else {
							Ability temp = Ability.abilityInitializer(ability);
							temp.setTarget(new Coordinate(total, locationY));
							movementSet.addAbilityItem(temp);
						}
					}
				}

				total = locationX - i;
				if ((total) > -1) {
					if (map.getArmy(total, locationY) != null) {
						if (ability.getAbilityAffectTo() == AFFECT_ENEMY) {
							if (getGroup(
									map.getArmy(total, locationY).getGroupID())
									.getSide() != side) {
								Ability temp = Ability
										.abilityInitializer(ability);
								temp.setTarget(new Coordinate(total, locationY));
								movementSet.addAbilityItem(temp);
							}
						} else if (ability.getAbilityAffectTo() == AFFECT_ALLY) {
							if (getGroup(
									map.getArmy(total, locationY).getGroupID())
									.getSide() == side) {
								Ability temp = Ability
										.abilityInitializer(ability);
								temp.setTarget(new Coordinate(total, locationY));
								movementSet.addAbilityItem(temp);
							}
						} else {
							Ability temp = Ability.abilityInitializer(ability);
							temp.setTarget(new Coordinate(total, locationY));
							movementSet.addAbilityItem(temp);
						}
					}
				}

				total = locationY + i;
				if ((total) < row) {
					if (map.getArmy(locationX, total) != null) {
						if (ability.getAbilityAffectTo() == AFFECT_ENEMY) {
							if (getGroup(
									map.getArmy(locationX, total).getGroupID())
									.getSide() != side) {
								Ability temp = Ability
										.abilityInitializer(ability);
								temp.setTarget(new Coordinate(locationX, total));
								movementSet.addAbilityItem(temp);
							}
						} else if (ability.getAbilityAffectTo() == AFFECT_ALLY) {
							if (getGroup(
									map.getArmy(locationX, total).getGroupID())
									.getSide() == side) {
								Ability temp = Ability
										.abilityInitializer(ability);
								temp.setTarget(new Coordinate(locationX, total));
								movementSet.addAbilityItem(temp);
							}
						} else {
							Ability temp = Ability.abilityInitializer(ability);
							temp.setTarget(new Coordinate(locationX, total));
							movementSet.addAbilityItem(temp);
						}
					}

					diff = range - i;

					for (j = 1; j < diff; j++) {
						subTotal = locationX + j;
						if (subTotal < column) {
							if (map.getArmy(subTotal, total) != null) {
								if (ability.getAbilityAffectTo() == AFFECT_ENEMY) {
									if (getGroup(
											map.getArmy(subTotal, total)
													.getGroupID()).getSide() != side) {
										Ability temp = Ability
												.abilityInitializer(ability);
										temp.setTarget(new Coordinate(subTotal,
												total));
										movementSet.addAbilityItem(temp);
									}
								} else if (ability.getAbilityAffectTo() == AFFECT_ALLY) {
									if (getGroup(
											map.getArmy(subTotal, total)
													.getGroupID()).getSide() == side) {
										Ability temp = Ability
												.abilityInitializer(ability);
										temp.setTarget(new Coordinate(subTotal,
												total));
										movementSet.addAbilityItem(temp);
									}
								} else {
									Ability temp = Ability
											.abilityInitializer(ability);
									temp.setTarget(new Coordinate(subTotal,
											total));
									movementSet.addAbilityItem(temp);
								}
							}
						}
						subTotal = locationX - j;
						if (subTotal > -1) {
							if (map.getArmy(subTotal, total) != null) {
								if (ability.getAbilityAffectTo() == AFFECT_ENEMY) {
									if (getGroup(
											map.getArmy(subTotal, total)
													.getGroupID()).getSide() != side) {
										Ability temp = Ability
												.abilityInitializer(ability);
										temp.setTarget(new Coordinate(subTotal,
												total));
										movementSet.addAbilityItem(temp);
									}
								} else if (ability.getAbilityAffectTo() == AFFECT_ALLY) {
									if (getGroup(
											map.getArmy(subTotal, total)
													.getGroupID()).getSide() == side) {
										Ability temp = Ability
												.abilityInitializer(ability);
										temp.setTarget(new Coordinate(subTotal,
												total));
										movementSet.addAbilityItem(temp);
									}
								} else {
									Ability temp = Ability
											.abilityInitializer(ability);
									temp.setTarget(new Coordinate(subTotal,
											total));
									movementSet.addAbilityItem(temp);
								}
							}
						}
					}
				}

				total = locationY - i;
				if ((total) > -1) {
					if (map.getArmy(locationX, total) != null) {
						if (ability.getAbilityAffectTo() == AFFECT_ENEMY) {
							if (getGroup(
									map.getArmy(locationX, total).getGroupID())
									.getSide() != side) {
								Ability temp = Ability
										.abilityInitializer(ability);
								temp.setTarget(new Coordinate(locationX, total));
								movementSet.addAbilityItem(temp);
							}
						} else if (ability.getAbilityAffectTo() == AFFECT_ALLY) {
							if (getGroup(
									map.getArmy(locationX, total).getGroupID())
									.getSide() == side) {
								Ability temp = Ability
										.abilityInitializer(ability);
								temp.setTarget(new Coordinate(locationX, total));
								movementSet.addAbilityItem(temp);
							}
						} else {
							Ability temp = Ability.abilityInitializer(ability);
							temp.setTarget(new Coordinate(locationX, total));
							movementSet.addAbilityItem(temp);
						}
					}

					diff = range - i;

					for (j = 1; j < diff; j++) {
						subTotal = locationX + j;
						if (subTotal < column) {
							if (map.getArmy(subTotal, total) != null) {
								if (ability.getAbilityAffectTo() == AFFECT_ENEMY) {
									if (getGroup(
											map.getArmy(subTotal, total)
													.getGroupID()).getSide() != side) {
										Ability temp = Ability
												.abilityInitializer(ability);
										temp.setTarget(new Coordinate(subTotal,
												total));
										movementSet.addAbilityItem(temp);
									}
								} else if (ability.getAbilityAffectTo() == AFFECT_ALLY) {
									if (getGroup(
											map.getArmy(subTotal, total)
													.getGroupID()).getSide() == side) {
										Ability temp = Ability
												.abilityInitializer(ability);
										temp.setTarget(new Coordinate(subTotal,
												total));
										movementSet.addAbilityItem(temp);
									}
								} else {
									Ability temp = Ability
											.abilityInitializer(ability);
									temp.setTarget(new Coordinate(subTotal,
											total));
									movementSet.addAbilityItem(temp);
								}
							}
						}

						subTotal = locationX - j;
						if (subTotal > -1) {
							if (map.getArmy(subTotal, total) != null) {
								if (ability.getAbilityAffectTo() == AFFECT_ENEMY) {
									if (getGroup(
											map.getArmy(subTotal, total)
													.getGroupID()).getSide() != side) {
										Ability temp = Ability
												.abilityInitializer(ability);
										temp.setTarget(new Coordinate(subTotal,
												total));
										movementSet.addAbilityItem(temp);
									}
								} else if (ability.getAbilityAffectTo() == AFFECT_ALLY) {
									if (getGroup(
											map.getArmy(subTotal, total)
													.getGroupID()).getSide() == side) {
										Ability temp = Ability
												.abilityInitializer(ability);
										temp.setTarget(new Coordinate(subTotal,
												total));
										movementSet.addAbilityItem(temp);
									}
								} else {
									Ability temp = Ability
											.abilityInitializer(ability);
									temp.setTarget(new Coordinate(subTotal,
											total));
									movementSet.addAbilityItem(temp);
								}
							}
						}
					}
				}
			}
		}
	}

	public final void evaluateSingleMovement(MovementSet movementSet, Army arm) {
		int point = 0;
		Group allyGroup = getGroup(arm.getGroupID());
		int x = movementSet.getLocationX();
		int y = movementSet.getLocationY();
		point = point + (this.getTotalMapObjectDefense(x, y) << 6);

		Building building = map.getBuilding(x, y);
		if (building != null) {
			int type = building.getBuildingType();
			if (isInSameSide(building.getGroupID(), allyGroup.getID())) {
				if (type == UNKNOWN_TYPE) {
					point += 800;
				} else if (type == PRODUCE_GOLD_TYPE) {
					point += 1100;
				}
				if (building.getGroupID() == arm.getGroupID()) {
					if (type == RESTORE_HP_TYPE) {
						point += ((DEFAULT_UNIT_HEALTH - arm.getHealth()) * arm
								.getRank());
					} else if (type == PRODUCE_ARMY_TYPE) {
						point += ((DEFAULT_UNIT_HEALTH - arm.getHealth()) * arm
								.getRank()) + 1300;
					} else {// if (building.getBuildingType() ==
						// HEAD_QUARTER_TYPE)
						point += ((DEFAULT_UNIT_HEALTH - arm.getHealth()) * arm
								.getRank()) + 1600;
					}
				} else {
					if (type == RESTORE_HP_TYPE) {
						point -= 600;
					} else if (type == PRODUCE_ARMY_TYPE) {
						point -= 900;
					} else {// if (building.getBuildingType() ==
						// HEAD_QUARTER_TYPE)
						point += 1000;
					}
				}

			} else {
				switch (type) {
				case UNKNOWN_TYPE:
					point += 700;
					break;
				case PRODUCE_GOLD_TYPE:
					point += 1000;
					break;
				case RESTORE_HP_TYPE:
					point += 1300;
					break;
				case PRODUCE_ARMY_TYPE:
					point += 1600;
					break;
				case HEAD_QUARTER_TYPE:
					point += 2000;
					break;
				}
			}
		}
		point = point
				- ((new Coordinate(x, y)).getDistance(allyGroup
						.getStrategyInfomation().getEnemyHQLocation()) << 10);
		movementSet.setPoint(point);
	}

	public final int evaluateMovement(MovementSet movementSet, Army arm) {
		int point = 0;
		int x = movementSet.getLocationX();
		int y = movementSet.getLocationY();
		point = point + (this.getTotalMapObjectDefense(x, y) << 6);

		Building building = map.getBuilding(x, y);
		if (building != null) {
			int type = building.getBuildingType();
			if (isInSameSide(arm.getGroupID(), building.getGroupID()) == true) {
				if (type == UNKNOWN_TYPE) {
					point += 800;
				} else if (type == PRODUCE_GOLD_TYPE) {
					point += 1100;
				}
				if (building.getGroupID() == arm.getGroupID()) {
					if (type == RESTORE_HP_TYPE) {
						point += ((DEFAULT_UNIT_HEALTH - arm.getHealth()) * arm
								.getRank());
					} else if (type == PRODUCE_ARMY_TYPE) {
						point += ((DEFAULT_UNIT_HEALTH - arm.getHealth()) * arm
								.getRank()) + 1300;
					} else {// if (building.getBuildingType() ==
						// HEAD_QUARTER_TYPE)
						point += ((DEFAULT_UNIT_HEALTH - arm.getHealth()) * arm
								.getRank()) + 1600;
					}
				} else {
					if (type == RESTORE_HP_TYPE) {
						point -= 600;
					} else if (type == PRODUCE_ARMY_TYPE) {
						point -= 900;
					} else {// if (building.getBuildingType() ==
						// HEAD_QUARTER_TYPE)
						point += 1000;
					}
				}
			} else {
				switch (type) {
				case UNKNOWN_TYPE:
					point += 700;
					break;
				case PRODUCE_GOLD_TYPE:
					point += 1000;
					break;
				case RESTORE_HP_TYPE:
					point += 1300;
					break;
				case PRODUCE_ARMY_TYPE:
					point += 1600;
					break;
				case HEAD_QUARTER_TYPE:
					point += 2000;
					break;
				}
			}
		}
		return point;
	}

	public final void evaluateAttackSet(MovementSet movementSet, Army arm) {
		ArrayList<AttackSet> atkSets = movementSet.getAttackSet();
		if (atkSets != null) {
			Ability temp = arm.getAttackAbility();
			for (AttackSet attackSet : atkSets) {
				temp.setTarget(attackSet.getCoordinate());
				temp.abilityManager(arm, this, true);
				attackSet.setPoint(attackSet.getPoint()
						+ temp.getAbilityPoint());
			}
		}
	}

	public final void evaluateAbilitySet(MovementSet movementSet, Army arm) {
		ArrayList<Ability> actionSet = movementSet.getAbilitySet();
		if (actionSet != null) {
			for (Ability act : actionSet) {
				act.abilityManager(arm, this, true);
			}
		}
	}

	public final AttackSet findBestAttack(ArrayList<AttackSet> attackSet) {
		int temp, maxPoint = Integer.MIN_VALUE;
		AttackSet maxAttackSet = null;
		for (AttackSet atkSet : attackSet) {
			temp = atkSet.getPoint();
			if (temp > maxPoint) {
				maxPoint = temp;
				maxAttackSet = atkSet;
			}
		}
		return maxAttackSet;
	}

	public final Ability findBestAbility(ArrayList<Ability> abilitySet) {
		int temp, maxPoint = Integer.MIN_VALUE;
		Ability maxAction = null;
		for (Ability action : abilitySet) {
			temp = action.getAbilityPoint();
			if (temp > maxPoint) {
				maxPoint = temp;
				maxAction = action;
			}
		}
		return maxAction;
	}

	public final Ability findBestAction(MovementSet movementSet, Army arm) {
		ArrayList<Ability> tempAbility = movementSet.getAbilitySet();
		ArrayList<AttackSet> tempAttack = movementSet.getAttackSet();
		AttackSet tempOccupy = movementSet.getOccupySet();
		Ability result = null;
		Ability maxAbility = findBestAbility(tempAbility);
		AttackSet maxAttack = findBestAttack(tempAttack);

		if (maxAbility != null) {
			if (maxAttack != null) {
				if (maxAttack.getPoint() > maxAbility.getAbilityPoint()) {
					result = arm.getAttackAbility();
					result.setTarget(maxAttack.getCoordinate());
				} else {
					result = maxAbility;
					result.setTarget(maxAbility.getTarget());
				}
			} else {
				result = maxAbility;
				result.setTarget(maxAbility.getTarget());
			}
		} else if (maxAttack != null) {
			result = arm.getAttackAbility();
			result.setTarget(maxAttack.getCoordinate());
		}

		if (result != null) {
			if (tempOccupy != null) {
				if (tempOccupy.getPoint() > result.getAbilityPoint()) {
					result = arm.getOccupyAbility();
					result.setTarget(tempOccupy.getCoordinate());
				}
			}
		} else if (tempOccupy != null) {
			result = arm.getOccupyAbility();
			result.setTarget(tempOccupy.getCoordinate());
		}

		return result;
	}

	public final ArrayList<Coordinate> findMovementPath(Coordinate current,
			Coordinate destination) {
		ArrayList<Coordinate> result = new ArrayList<Coordinate>();
		Coordinate currentLocation = destination;
		MovementSet moveSet;

		while (currentLocation.isEqual(current) == false) {
			result.add(currentLocation);
			moveSet = map.getMovementSet(currentLocation.getLocationX(),
					currentLocation.getLocationY());

			if (moveSet == null) {
				for (AlternativeCoordinate alter : alternativePath) {
					if (alter.getDestination().isEqual(currentLocation) == true) {
						currentLocation = new Coordinate(alter
								.getCurrentPosition().getLocationX(), alter
								.getCurrentPosition().getLocationY());
						break;
					}
				}
			} else {
				currentLocation = new Coordinate(moveSet.getLocationX(),
						moveSet.getLocationY());
			}
		}

		result.add(current);

		return result;
	}

	public final boolean isMoveable(Army arm) {
		int locationX = arm.getLocationX();
		int locationY = arm.getLocationY();

		int movement = arm.getTotalMovement();

		int i = locationX - movement;
		int j = locationY - movement;

		int m = locationX + movement;
		int n = locationY + movement;

		if (i < 0) {
			i = 0;
		}
		if (j < 0) {
			j = 0;
		}

		if (m > map.getNumberOfColumn()) {
			m = map.getNumberOfColumn();
		}
		if (n > map.getNumberOfRow()) {
			n = map.getNumberOfRow();
		}

		this.generateMove(arm, 0);

		MovementSet moveSet;

		for (int k = i; k < m; k++) {
			for (int l = j; l < n; l++) {
				moveSet = map.getMovementSet(k, l);
				if (moveSet != null) {
					if (moveSet.getCoordinate().isEqual(arm.getCoordinate()) == false) {
						return true;
					}
				}
			}
		}
		return false;
	}

	public MovementSet getMovementAttackPath(Army attackArmy, int locationX,
			int locationY) {
		int x = attackArmy.getLocationX();
		int y = attackArmy.getLocationY();
		generateMove(attackArmy, 0);

		int movement = attackArmy.getTotalMovement();
		int i1 = x - movement;
		int j1 = y - movement;

		int m1 = x + movement;
		int n1 = y + movement;

		if (i1 < 0) {
			i1 = 0;
		}
		if (j1 < 0) {
			j1 = 0;
		}

		if (m1 > map.getNumberOfColumn()) {
			m1 = map.getNumberOfColumn();
		}
		if (n1 > map.getNumberOfRow()) {
			n1 = map.getNumberOfRow();
		}

		MovementSet moveSet, resultMoveSet = null;
		int tempPoint, resultPoint = Integer.MIN_VALUE;

		for (int k1 = i1; k1 < m1; k1++) {
			for (int l1 = j1; l1 < n1; l1++) {
				moveSet = map.getMovementSet(k1, l1);
				if (moveSet != null) {
					generateAttackSet(moveSet, attackArmy, k1, l1);

					ArrayList<AttackSet> coor = moveSet.getAttackSet();
					for (AttackSet position : coor) {
						if (position.getLocationX() == locationX
								&& position.getLocationY() == locationY) {
							tempPoint = evaluateMovement(moveSet, attackArmy);
							if (tempPoint > resultPoint) {
								resultPoint = tempPoint;
								resultMoveSet = new MovementSet(k1, l1);
								resultMoveSet.addAttackItem(
										position.getLocationX(),
										position.getLocationY());
							}
							break;
						}
					}
				}
			}
		}
		return resultMoveSet;
	}

	public MovementSet getMovementAbilityPath(Army attackArmy, Ability ability,
			int locationX, int locationY) {
		int x = attackArmy.getLocationX();
		int y = attackArmy.getLocationY();
		generateMove(attackArmy, 0);

		int movement = attackArmy.getTotalMovement();
		int i1 = x - movement;
		int j1 = y - movement;

		int m1 = x + movement;
		int n1 = y + movement;

		if (i1 < 0) {
			i1 = 0;
		}
		if (j1 < 0) {
			j1 = 0;
		}

		if (m1 > map.getNumberOfColumn()) {
			m1 = map.getNumberOfColumn();
		}
		if (n1 > map.getNumberOfRow()) {
			n1 = map.getNumberOfRow();
		}

		MovementSet moveSet, resultMoveSet = null;
		int tempPoint, resultPoint = Integer.MIN_VALUE;

		for (int k1 = i1; k1 < m1; k1++) {
			for (int l1 = j1; l1 < n1; l1++) {
				moveSet = map.getMovementSet(k1, l1);
				if (moveSet != null) {
					generateAbilitySet(moveSet, attackArmy, k1, l1, ability);

					ArrayList<Ability> coor = moveSet.getAbilitySet();
					for (Ability position : coor) {
						Coordinate abilityCoor = position.getTarget();
						if (abilityCoor.getLocationX() == locationX
								&& abilityCoor.getLocationY() == locationY) {
							tempPoint = evaluateMovement(moveSet, attackArmy);
							if (tempPoint > resultPoint) {
								resultPoint = tempPoint;
								resultMoveSet = new MovementSet(k1, l1);
								resultMoveSet.addAttackItem(
										abilityCoor.getLocationX(),
										abilityCoor.getLocationY());
							}
							break;
						}
					}
				}
			}
		}
		return resultMoveSet;
	}

	public final CompleteActionSet generateSingleMove(Army arm, int initialPoint) {
		int locationX = arm.getLocationX();
		int locationY = arm.getLocationY();

		int movement = arm.getTotalMovement();
		CompleteActionSet finalAction;
		int i = locationX - movement;
		int j = locationY - movement;

		int m = locationX + movement;
		int n = locationY + movement;

		if (i < 0) {
			i = 0;
		}
		if (j < 0) {
			j = 0;
		}

		if (m > map.getNumberOfColumn()) {
			m = map.getNumberOfColumn();
		}
		if (n > map.getNumberOfRow()) {
			n = map.getNumberOfRow();
		}

		this.generateMove(arm, initialPoint);

		MovementSet moveSet;
		int maxPoint = Integer.MIN_VALUE, tempPoint = Integer.MIN_VALUE;
		Ability tempAction, maxAction = null;
		Coordinate destination = null;

		for (int k = i; k < m; k++) {
			for (int l = j; l < n; l++) {
				moveSet = map.getMovementSet(k, l);
				if (moveSet != null) {
					this.evaluateSingleMovement(moveSet, arm);
					this.generateAttackSet(moveSet, arm, k, l);
					this.evaluateAttackSet(moveSet, arm);
					this.generateAndEvaluateOccupySet(moveSet, arm, k, l);
					this.generateAbilitySet(moveSet, arm, k, l);
					this.evaluateAbilitySet(moveSet, arm);

					tempAction = findBestAction(moveSet, arm);
					tempPoint = moveSet.getPoint();

					if (tempAction != null) {
						tempPoint += tempAction.getAbilityPoint();
					}

					if (tempPoint > maxPoint) {
						destination = new Coordinate(k, l);
						if (tempAction != null) {
							maxAction = Ability.abilityInitializer(tempAction);
							maxAction.setTarget(new Coordinate(tempAction
									.getTarget()));
						} else {
							maxAction = null;
						}
						maxPoint = tempPoint;
					}
				}
			}
		}

		if (maxAction != null) {
			finalAction = new CompleteActionSet(arm.getCoordinate(),
					destination, maxAction);
		} else {
			finalAction = new CompleteActionSet(arm.getCoordinate(),
					destination, null);
		}
		finalAction.setMovementPath(findMovementPath(arm.getCoordinate(),
				destination));

		return finalAction;
	}
}
